﻿using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using AgileShare.Framework.Core;
using AgileShare.Framework.SiteProvisioning.Definitions;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace AgileShare.Framework.SiteProvisioning.Helpers
{
	public static class SiteDefinitionHelper
	{
		/// <summary>
		/// Ensures the sites.
		/// </summary>
		/// <param name="siteDefs">The site defs.</param>
		/// <param name="web">The web.</param>
		/// <param name="updateIfExists">if set to <c>true</c> [update if exists].</param>
		/// <param name="replaceListContentTypes">if set to <c>true</c> [replace list content types].</param>
		/// <param name="updateViews">if set to <c>true</c> [update views].</param>
		public static void EnsureSites(IEnumerable<SiteDefinition> siteDefs, SPWeb web, bool updateIfExists = false)
		{
			foreach (SiteDefinition siteDef in siteDefs)
			{
				EnsureSite(siteDef, web, updateIfExists);
			}
		}

		/// <summary>
		/// Ensures the site.
		/// </summary>
		/// <param name="definition">The site def.</param>
		/// <param name="web">The web.</param>
		/// <param name="updateIfExists">if set to <c>true</c> [update if exists].</param>
		/// <param name="replaceListContentTypes">if set to <c>true</c> [replace list content types].</param>
		/// <param name="updateViews">if set to <c>true</c> [update views].</param>
		public static void EnsureSite(SiteDefinition definition, SPWeb web, bool updateIfExists = false)
		{
			TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.Information,
				"Ensuring Site '{0}' in parent Site '{1};'", definition.Name, web.Url);

			try
			{
				SPWeb newWeb = web.Webs.FirstOrDefault(x => x.Name == definition.Name);

				if (newWeb == null)
				{
					newWeb = web.Webs.Add(definition.Name, definition.Title, definition.Description, definition.NLCID, definition.TemplateName,
						definition.UseUniquePermissions, definition.ConvertIfThere);

					UpdateSite(definition, newWeb, updateIfExists);
				}
				else if (updateIfExists)
				{
					newWeb.Name = definition.Name;
					newWeb.Title = definition.Title;
					newWeb.Description = definition.Description;

					UpdateSite(definition, newWeb, updateIfExists);
				}
				
				if (newWeb != null)
				{
					TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SPFieldHelper, TraceProviderSeverity.Monitorable,
						"Successfully ensured Site '{0}' in parent Site '{1}';", definition.Name, web.Url);

					newWeb.Dispose();
				}
			}
			catch (Exception ex)
			{
				TraceProvider.Log(TraceProviderCategories.Default, (uint)TraceProviderEventIds.SiteProvisioning, TraceProviderSeverity.CriticalError, ex,
					"Failed to ensure Site '{0}' in parent Site '{1}';", definition.Name, web.Url);
			}
		}

		/// <summary>
		/// Updates the site.
		/// </summary>
		/// <param name="siteDef">The site def.</param>
		/// <param name="updateIfExists">if set to <c>true</c> [update if exists].</param>
		/// <param name="replaceListContentTypes">if set to <c>true</c> [replace list content types].</param>
		/// <param name="updateViews">if set to <c>true</c> [update views].</param>
		/// <param name="newWeb">The new web.</param>
		private static void UpdateSite(SiteDefinition siteDef, SPWeb newWeb, bool updateIfExists = false)
		{
			ListDefinitionHelper.EnsureLists(siteDef.ListInstanceDefinitions, newWeb, updateIfExists);

			foreach (Guid featureId in siteDef.SiteFeatureIds)
			{
				var feature = newWeb.Features.SingleOrDefault(sf => sf.DefinitionId == featureId);
				if (feature == null)
				{
					newWeb.Features.Add(featureId);
				}
			}
		}
	}
}
